package panda.index.bplustree;

import panda.record.*;
import panda.file.*;
import panda.query.struct.*;
import panda.transaction.Transaction;

public class TreeLeaf {
	private int currentslot;
	private TreePage content;
	private String filename;
	private Constant searchkey;
	private TableToken tbl;
	private Transaction tx;

	TreeLeaf(Block blk, TableToken tt, Constant sk, Transaction t) {
		tbl = tt;
		tx = t;
		filename = blk.getFileName();
		searchkey = sk;
		content = new TreePage(blk, tbl, tx);
		currentslot = content.findSlotBefore(searchkey);
	}

	public boolean next() {
		currentslot++;

		/*while (currentslot >= content.getRecordNum()) {
			if (!moveToOverflow())
				return false;
		}*/
		
		if (currentslot >= content.getRecordNum()) return moveToOverflow();
		else if (content.getData(currentslot).compareTo(searchkey) == 0) return true;
		else return moveToOverflow();
		
		//return (content.getData(currentslot).compareTo(searchkey) == 0);
	}

	public boolean getNext() {
		currentslot++;

		if (currentslot < content.getRecordNum()) {
			return true;
		} else {
			if (moveToOverflow()) {
				currentslot = 0;
				return true;
			} else {
				return moveToNextLeaf();
			}
		}
	}

	public Constant getDataVal() {
		return content.getData(currentslot);
	}

	public TupleToken SmallestBiggerTupleToken() {
		currentslot++;
		while (currentslot <= content.getRecordNum()) {
			if (content.getData(currentslot).compareTo(searchkey) == 0) {
				currentslot++;
			} else {
				break;
			}
		}

		if (content.getData(currentslot).compareTo(searchkey) != 0) {
			return getTupleToken();
		} else {
			//content = content.nextLeafPage;
			//Block tempblk = new Block(tbl.getFilename(), content.nextLeafPageBlockNum);
			//content = new TreePage(tempblk, tbl, tx);
			return getTupleToken();
		}
	}

	public boolean moveToNextLeaf() {
		/*if (content.nextLeafPage == null)
			return false;*/
		if (content.nextLeafPageBlockNum == -1) return false;
		//if (content.getBlockNum() == -1) return false;
        
		//content = content.nextLeafPage;
		//Block nextblk = new Block(tbl.getFilename(), content.getBlockNum());
		//content = new TreePage(nextblk, tbl, tx);
		
		currentslot = 0;

		return true;
	}

	// TODO
	public void printRecord() {
		content.print();
	}

	public boolean notLastLeaf() {
		//return (content.nextLeafPage != null);
		return (content.nextLeafPageBlockNum != -1);
		//return (content.getBlockNum() != -1);
	}

	public boolean isAtTail() {
		currentslot++;
		return (currentslot >= content.getRecordNum() && !moveToOverflow());
	}

	public TupleToken getTupleToken() {
		return (content.getTupleToken(currentslot));
	}

	public void delete(TupleToken tt) {
		while (next()) {
			if (getTupleToken().equals(tt)) {
				content.deleteTupleToken(currentslot);
				return;
			}
		}
	}

	public void close() {
		content.close();
	}

	public DirEntry insertTupleToken(TupleToken tt) {
		currentslot++;
		content.insertLeaf(currentslot, searchkey, tt);

		if (!content.isFull())
			return null;

		Constant firstkey = content.getData(0);
		Constant lastkey = content.getData(content.getRecordNum() - 1);

		if (lastkey.compareTo(firstkey) == 0) {
			Block newblk = content.split(1, content.getLevel());
			content.setLevel(newblk.getBlockNumber());
			return null;
		} else {
			int pos = content.getRecordNum() / 2;
			Constant key = content.getData(pos);
			if (key.compareTo(firstkey) == 0) {
				while (content.getData(pos).compareTo(key) == 0) {
					pos++;
				}
				key = content.getData(pos);
			} else {
				while (content.getData(pos - 1).compareTo(key) == 0) {
					pos--;
				}
			}
			
			Block blk = content.split(pos, -1);
			//content.nextLeafPage = new TreePage(blk, tbl, tx);
			content.nextLeafPageBlockNum = blk.getBlockNumber();
			//content.setBlockNum(blk.getBlockNumber());
			return new DirEntry(key, blk.getBlockNumber());
		}
	}
	
	public boolean searchTupleToken(Constant searchkey) {
		return content.isInLeaf(searchkey);
	}

	// TODO
	private boolean moveToOverflow() {
		int blkno = content.getLevel();
		Constant key = content.getData(0);
		// whether it is necessary to test '!searchkey.equals(firstkey)'
		if (blkno < 0 || searchkey.compareTo(key) != 0)
			return false;

		content.close();
		Block newblk = new Block(filename, blkno);
		content = new TreePage(newblk, tbl, tx);
		currentslot = 0;

		return true;
	}
}